#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "esp_log.h"
#include "esp_mac.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <esp_log.h>
#include <driver/uart.h>
#include <lwip/sockets.h>
#include <sys/errno.h>


#define _MaxMB 1024

// 带超时的写操作
int write_timeout(int fd, unsigned int wait_seconds) {
    int ret = 0;
    if (wait_seconds > 0) {
        fd_set write_fdset;
        struct timeval timeout;

        FD_ZERO(&write_fdset);
        FD_SET(fd, &write_fdset);

        timeout.tv_sec = wait_seconds;
        timeout.tv_usec = 0;

        do {
            ret = select(fd + 1, NULL, &write_fdset, NULL, &timeout);
        } while (ret < 0 && errno == EINTR);

        if (ret == 0) {
            ret = -1;
            errno = ETIMEDOUT;
        } else if (ret == 1) {
            return 0;
        }
    }
    return ret;
}

// 带超时的读操作
int read_timeout(int fd, unsigned int wait_mills) {
    int ret = 0;
    int nRet = 0;
    int tv_sec = 0;
    int tv_usec = 0;
    if (wait_mills > 0) {
        fd_set read_fdset;
        struct timeval timeout = {0, 0};
        tv_sec = wait_mills / 1000;
        tv_usec = wait_mills % 1000 * 1000;

        do {
            FD_ZERO(&read_fdset);
            FD_SET(fd, &read_fdset);

            timeout.tv_sec = tv_sec;
            timeout.tv_usec = tv_usec;

            nRet = select(fd + 1, &read_fdset, NULL, NULL, &timeout);
        } while (nRet < 0 && errno == EINTR);

        if (nRet == 0) {
            ret = -1;
            errno = ETIMEDOUT;
        } else if (nRet == 1) {
            ret = 0;
        } else {
            ESP_LOGE("read_timeout", "nRet = %d, errno = %d, strerror = %s", nRet, errno, strerror(errno));
        }
        FD_CLR(fd, &read_fdset);
    }
    return ret;
}


// 判断是大端存储还是小端存储
int IsBigEndian() {
    short int x;
    char x0, x1;
    x = 0x1122;
    x0 = *((char *)&x);
    x1 = *((char *)&x + 1);
    if (x0 == 0x11 && x1 == 0x22) {
        return 1;
    } else if (x0 == 0x22 && x1 == 0x11) {
        return 0;
    }
    return 0;
}


// 设置保持活动状态
void set_keepalive(int fd) {
    int val = 1;
    int nRet = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&val, sizeof(val));
    if (nRet < 0) {
        ESP_LOGE("set_keepalive", "setsockopt error: %s", strerror(errno));
    }
}

// 大端转小端 或 小端转大端
uint32_t reversebytes_uint32t(uint32_t value) {
    return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
           (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}

// 写包
int writepkg(int sockfd, char *pSendBuf, int bufLen) {
    //const char *TAG = "safe_send";
    int nleft;
    int nwritten;
    int talNWritten = 0;
    const char *ptr;
    ptr = (char *)pSendBuf;
    nleft = bufLen;
    while (nleft > 0) {
        // 在任务中定期检查
        //UBaseType_t watermark = uxTaskGetStackHighWaterMark(NULL);
        //ESP_LOGI(TAG, "Stack free: %u words (%u bytes)", watermark, watermark * 4);
        if ((nwritten = send(sockfd, ptr, nleft, 0)) <= 0) {
            if (errno == EINTR) {
                nwritten = 0;
            } else {
                return -1;
            }
        }
        nleft -= nwritten;
        ptr += nwritten;
        talNWritten += nwritten;
    }
    return talNWritten;
}


/**
 * 安全发送数据到socket，支持连续调用和自动重试
 * @param sockfd 套接字描述符
 * @param data 待发送数据的指针
 * @param len 数据长度（字节）
 * @return 成功返回实际发送的字节数，失败返回-1
 */
int writepkg2(int sockfd, void *data, int len) {
    const char *TAG = "safe_send";
    const int MAX_RETRIES = 1;    // 最大重试次数
    const TickType_t RETRY_DELAY = 100 / portTICK_PERIOD_MS;  // 重试延迟（毫秒）
    
    if (sockfd < 0 || data == NULL || len == 0) {
        ESP_LOGE(TAG, "Invalid parameters: sockfd=%d, data=%p, len=%zu", sockfd, data, len);
        return -1;
    }
    
    size_t total_sent = 0;
    int retries = 0;
    
    while (total_sent < len) {
        ESP_LOGI(TAG,"send start : socket:%d, len: %d",sockfd,len);
        // 在任务中定期检查
        UBaseType_t watermark = uxTaskGetStackHighWaterMark(NULL);
        ESP_LOGI(TAG, "Stack free: %u words (%u bytes)", watermark, watermark * 4);
        ssize_t sent = send(sockfd, (const char*)data + total_sent, len - total_sent, 0);
        ESP_LOGI(TAG,"send end-- : len: %d",sent);
        
        if (sent < 0) {
            // 发送失败，检查错误类型
            switch (errno) {
                case EINTR:
                case EAGAIN:
                    // 可重试的错误
                    if (retries++ < MAX_RETRIES) {
                        ESP_LOGW(TAG, "Temporary error (errno=%d), retry %d/%d", errno, retries, MAX_RETRIES);
                        vTaskDelay(RETRY_DELAY);
                        continue;
                    } else {
                        ESP_LOGE(TAG, "Max retries reached for temporary error (errno=%d)", errno);
                        return -1;
                    }
                    
                case EPIPE:
                case ECONNRESET:
                case ENOTCONN:
                    // 连接已断开
                    ESP_LOGE(TAG, "Connection lost (errno=%d), closing socket", errno);
                    close(sockfd);
                    return -1;
                    
                default:
                    // 其他不可恢复的错误
                    ESP_LOGE(TAG, "Fatal send error (errno=%d)", errno);
                    return -1;
            }
        }
        
        total_sent += sent;
        retries = 0;  // 重置重试计数器
    }
    
    return total_sent;
}

// 新的套接字
int newsocket(unsigned char *pHost, unsigned int hostLen, unsigned int port) {
    struct sockaddr_in servaddr;
    char *host = NULL;
    int sockfd;

    memset(&servaddr, 0, sizeof(servaddr));
    host = malloc(48);
    memset(host,0,48);
    memcpy(host, pHost, hostLen);

    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);
    servaddr.sin_addr.s_addr = inet_addr(host);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        ESP_LOGE("newsocket", "Create Socket Failed: %s", strerror(errno));
        free(host);
        return -1;
    }

    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
        ESP_LOGE("newsocket", "Connect Failed: %s", strerror(errno));
        closesocket(sockfd);
        free(host);
        return -1;
    }

    free(host);
    return sockfd;
}

// 初始化套接字
int initsock() {
    return 0;
}

// 关闭RYn套接字
int CloseRYnSocket(int sockfd) {
    return close(sockfd);
}


// 写FeiLu协议包
int WriteFeiLuProtocolPkg(int sockfd, char *data, int data_len) {
    char *sendBUF = (char *)heap_caps_malloc(5 + data_len, MALLOC_CAP_INTERNAL);
    if (sendBUF == NULL) {
        ESP_LOGE("WriteFeiLuProtocolPkg", "Memory allocation failed");
        return -1;
    }
    char sign_def[1] = {0x88};
    int nRet;

    memcpy(sendBUF, sign_def, 1);
    memcpy(sendBUF + 1, &data_len, 4);
    memcpy(sendBUF + 1 + 4, data, data_len);

    nRet = writepkg(sockfd, sendBUF, 5 + data_len);

    heap_caps_free(sendBUF);
    return nRet;
}


// utf8转ucs2
int utf8_to_ucs2(unsigned char *in, int ilen, unsigned char *out, int olen) {
    unsigned char *inoffset = in;
    unsigned char *inend = in + ilen;

    int ret = 0;
    while (inoffset < inend && ret + 2 <= olen) {
        unsigned short temp1, temp2;

        unsigned char *one = inoffset;
        unsigned short ucs2_code = 0;

        if (0x00 == (*one & 0x80)) {
            ucs2_code = (unsigned short)*one;
            inoffset++;
            memcpy(out + ret, &ucs2_code, 2);
            ret += 2;
            continue;
        } else if (0xc0 == (*one & 0xe0) && 0x80 == (*(one + 1) & 0xc0)) {
            temp1 = (unsigned short)(*one & 0x1f);
            temp1 <<= 6;
            temp1 |= (unsigned short)(*(one + 1) & 0x3f);
            ucs2_code = temp1;
            inoffset += 2;
            memcpy(out + ret, &ucs2_code, 2);
            ret += 2;
            continue;
        } else if (0xe0 == (*one & 0xf0) && 0x80 == (*(one + 1) & 0xc0) && 0x80 == (*(one + 2) & 0xc0)) {
            temp1 = (unsigned short)(*one & 0x0f);
            temp1 <<= 12;
            temp2 = (unsigned short)(*(one + 1) & 0x3F);
            temp2 <<= 6;
            temp1 = temp1 | temp2 | (unsigned short)(*(one + 2) & 0x3F);
            ucs2_code = temp1;
            inoffset += 3;
            memcpy(out + ret, &ucs2_code, 2);
            ret += 2;
            continue;
        } else {
            break;
        }
    }
    return ret;
}

// 16位 大小端转换
int ucs2_swap_endian(char *in, int ilen) {
    int i = 0;
    int max_len = ilen / 2 * 2;
    for (i = 0; i < max_len; i += 2) {
        uint16_t _16 = 0;
        uint16_t _16_n = 0;
        memcpy(&_16, in + i, 2);
        _16_n = htons(_16);
        memcpy(in + i, &_16_n, 2);
    }
    return 0;
}

// ucs2转utf8
int ucs2_to_utf8(unsigned char *in, int ilen, unsigned char *out, int olen) {
    int length = 0;
    unsigned char *start = NULL;
    unsigned char *pout = out;
    if (!out) return length;
    for (start = in; start != NULL && start < in + ilen - 1; start += 2) {
        unsigned short ucs2_code = *(unsigned short *)start;
        if (0x0080 > ucs2_code) {
            if (length + 1 > olen) return -1;

            *pout = (char)*start;
            length++;
            pout++;
        } else if (0x0800 > ucs2_code) {
            if (length + 2 > olen) return -1;
            *pout = ((char)(ucs2_code >> 6)) | 0xc0;
            *(pout + 1) = ((char)(ucs2_code & 0x003F)) | 0x80;
            length += 2;
            pout += 2;
        } else {
            if (length + 3 > olen) return -1;

            *pout = ((char)(ucs2_code >> 12)) | 0xE0;
            *(pout + 1) = ((char)((ucs2_code & 0x0FC0) >> 6)) | 0x80;
            *(pout + 2) = ((char)(ucs2_code & 0x003F)) | 0x80;
            length += 3;
            pout += 3;
        }
    }

    return length;
}

// 读取包
int readpkg(int sockfd, char *pRecvBuf, int bufLen) {
    return recv(sockfd, pRecvBuf, bufLen, 0);
}